package edu.ntu.cloudroid.xacml.obligation;

import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;


import com.sun.xacml.Obligation;
import com.sun.xacml.attr.BooleanAttribute;
import com.sun.xacml.attr.DoubleAttribute;
import com.sun.xacml.attr.IntegerAttribute;
import com.sun.xacml.attr.StringAttribute;
import com.sun.xacml.ctx.Attribute;
import com.sun.xacml.ctx.RequestCtx;
import com.sun.xacml.ctx.Subject;

import edu.ntu.cloudroid.model.IDs;
import edu.ntu.cloudroid.model.data.AbstractData;
import edu.ntu.cloudroid.model.data.DetachedData;
import edu.ntu.cloudroid.model.data.LocationData;
import edu.ntu.cloudroid.model.data.VitalSignData;
import edu.ntu.cloudroid.model.data.VitalSignInfo;
import edu.ntu.cloudroid.model.function.stats.IDataStats;
import edu.ntu.cloudroid.model.policy.SimpleFiltering;
import edu.ntu.cloudroid.model.profile.ProfileData;
import edu.ntu.cloudroid.server.backendservice.DataService;
import edu.ntu.cloudroid.server.backendservice.FriendService;
import edu.ntu.cloudroid.xacml.Utilities;
import edu.ntu.cloudroid.xacml.XACMLException;
import edu.ntu.cloudroid.xacml.XACMLStrings;

/**
 * Simple statistic (summary). Basic functions are most frequent location, max,
 * min, count, etc.
 * 
 */
public class StatsObligation implements ObligationHandle {

	@Override
	public List<DetachedData> processObligation(ProfileData subject,
			ProfileData resource, RequestCtx requestCtx, Obligation o)
			throws Exception {
		List<Attribute> assignments = o.getAssignments();
		int functionId = 0;
		int colIdx = 0;
		boolean isInputRequired = false;
		
		for (Attribute a : assignments) {
			if (a.getId().equals(new URI(XACMLStrings.ATTR_Stat_FunctionId))) {
				IntegerAttribute attr = (IntegerAttribute) a.getValue();
				functionId = (int) attr.getValue();
			}
			if (a.getId()
					.equals(new URI(XACMLStrings.ATTR_Filtering_ColumnIdx))) {
				IntegerAttribute attr = (IntegerAttribute) a.getValue();
				colIdx = (int) attr.getValue();
			}
			if (a.getId()
					.equals(new URI(XACMLStrings.ATTR_Input_Required))) {
				BooleanAttribute attr = (BooleanAttribute) a.getValue();
				isInputRequired = attr.getValue();
			}
		}
		return this.evaluateStats(subject, resource, requestCtx, colIdx,
				IDs.getStatsFunction(functionId), isInputRequired);
	}

	private List<DetachedData> evaluateStats(ProfileData subject,
			ProfileData resource, RequestCtx requestCtx, int colIdx,
			IDataStats func, boolean isInputRequired) throws Exception {
		List<DetachedData> list = new ArrayList<DetachedData>();
		List<AbstractData> allData = DataService.getAllData(resource, resource.getDataId());
		if (isInputRequired)
			allData = this.filterData(allData, requestCtx, resource.getDataId(), colIdx);
		
		AbstractData ad = (AbstractData)func.getStats(allData, colIdx);
		if (ad==null)
			return list;
		list.add(ad.detach(colIdx));
		
		//for this obligation, no need to update friend's latest timestamp
		return list;
	}

	//filter out the data where the location is the same as what given in the input
	private List<AbstractData> filterData(List<AbstractData> allData,
			RequestCtx requestCtx, int dataId, int colIdx) throws Exception {
		List<AbstractData> list = new ArrayList<AbstractData>();
		AbstractData dataFromRequest = ((AbstractData) DataService
				.getAbstractDataObject(dataId)).getDataFromRequest(requestCtx);

		for (AbstractData ad : allData) {
			if (ad.compareTo(dataFromRequest, colIdx) == 0)
				list.add(ad);
		}
		return list;
	}	
}
